#pragma once

#include <string>
#include <iostream>

// 计算器业务 - 自定义协议
namespace ComputerData
{
    
    #define SPACER "\r\n"
    #define SPACERLEN (sizeof(SPACER) - 1)

    // 请求
    class Request
    {
    public:
        Request() = default;
        Request(int x, int y, char op)
        :_x(x), _y(y), _op(op)
        {}

        // 序列化
        // 序列化格式: length\r\n_x _op _y\r\n
        std::string Serialize()
        {
            std::string str = std::to_string(_x);
            str += ' ';
            str += _op;
            str += ' ';
            str += std::to_string(_y);

            std::string header = std::to_string(str.size());
            return header + SPACER + str + SPACER;
        }

        // 反序列化
        // 提取到对应的元素中去
        // length\r\n_x _op _y\r\n
        // 5\r\n1 + 1\r\n
        bool Deserialization(const std::string& str)
        {
            // 首先，到达这里的str必须是上述样例的模样，不能多一个字符或者少一个字符
            // 下面进行字符串解析，如果一个存在不遵守，那么就无法提取成功
            size_t index1 = str.find(SPACER, 0);
            if (index1 == std::string::npos) return false;
            int length = atoi(str.substr(0, index1).c_str());

            size_t begin1 = index1 + SPACERLEN;
            size_t index2 = str.find(' ', begin1);
            if (index2 == std::string::npos) return false;
            _x = atoi(str.substr(begin1, index2 - begin1).c_str());

            size_t begin2 = index2 + 1;
            size_t index3 = str.find(' ', begin2);
            if (index3 == std::string::npos) return false;
            _op = str[index3 - 1];

            size_t begin3 = index3 + 1;
            size_t index4 = str.find(SPACER, begin3);
            if (index4 == std::string::npos) return false;
            _y = atoi(str.substr(begin3, index4 - begin3).c_str());

            // std::cout << length << " x:" << _x << " op:" << _op << " y:" << _y << std::endl;
            return true;
        }

        int _x;
        int _y;
        char _op;
    };

    // 响应
    class Response
    {
    public:
        Response() = default;
        Response(int code, int result)
        :_code(code), _result(result)
        {}

        // 序列化
        // 序列化格式: length\r\ncode result\r\n
        std::string Serialize()
        {
            std::string str = std::to_string(_code);
            str += ' ';
            str += std::to_string(_result);

            std::string header = std::to_string(str.size());
            return header + SPACER + str + SPACER;
        }

        bool Deserialization(const std::string& str)
        {
            // 首先，到达这里的str必须是上述样例的模样，不能多一个字符或者少一个字符
            // 下面进行字符串解析，如果一个存在不遵守，那么就无法提取成功
            size_t index1 = str.find(SPACER, 0);
            if (index1 == std::string::npos) return false;
            int length = atoi(str.substr(0, index1).c_str());

            size_t begin1 = index1 + SPACERLEN;
            size_t index2 = str.find(' ', begin1);
            if (index2 == std::string::npos) return false;
            _code = atoi(str.substr(begin1, index2 - begin1).c_str());

            size_t begin2 = index2 + 1;
            size_t index3 = str.find(SPACER, begin2);
            if (index3 == std::string::npos) return false;
            _result = atoi(str.substr(begin2, index3 - begin2).c_str());

            // std::cout << length << " code:" << _code << " result:" << _result << std::endl;
            return true;
        }

        int _code;  // 状态码
        int _result; // 结果
    };

    // 11\r\n121342 + 12\r\n 17 - 2*2 - 2 = 17-6 = 11
    std::string Decode(std::string& str)
    {
        // 解码，即必须检查当前读取的是否是完整的数据，如果不是就继续读取
        // 首先，开头必须是数字
        size_t index1 = str.find(SPACER, 0);
        if (index1 == std::string::npos) return "";
        int length = atoi(str.substr(0, index1).c_str());
        int pos = str.size() - 2 * SPACERLEN - index1;
        if (pos >= length)
        {
            // 说明此时长度已经可以提取了，修改返回即可
            std::string s = str.substr(0, length + 2 * SPACERLEN + index1);
            str.erase(0, length + 2 * SPACERLEN + index1);  // 删掉，此时外面的str为+=
            return s;
        }
        else return "";  // 否则返回空串

    }
}